package wisp.game;

import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import wisp.dataObjects.Statistics;
import wisp.dataObjects.WispCharacter;
import wisp.gui.SkillBar;
import wisp.gui.SkillWindow;

import com.golden.gamedev.object.Timer;

public class Elementalist extends PlayerSprite {

	private Timer decayCDTimer;
    private Timer decayDurationTimer;
    
    private Timer restorationCDTimer;
    private Timer restorationCastTimer;
    private Timer restorationDurationTimer;
    
    private Timer flareCDTimer;
    private Timer flareCastTimer;
    
    private int decayDurationCtr;
    
    private boolean decayOnCoolDown;
    private boolean decayDuration;
    private boolean restorationOnCoolDown;
    private boolean restorationCasting;
    private boolean restorationDuration;
    private boolean flareOnCoolDown;
    private boolean flareCasting;
    
    private CharacterSprite targetDecay;
    
    private int decaySkillLevel;
    private int restorationSkillLevel;
    private int flareSkillLevel;
    
    public Elementalist(String name, MainGame game, BufferedImage[] images, double x, double y) {
		super(name, game, images, x, y);
		
		decayCDTimer = new Timer(8000);
		decayCDTimer.setActive(false);
		decayDurationTimer = new Timer(1000);
		decayDurationTimer.setActive(false);
		restorationCDTimer = new Timer(120000);
		restorationCDTimer.setActive(false);
		restorationCastTimer = new Timer(2000);
		restorationCastTimer.setActive(false);
		restorationDurationTimer = new Timer(90000);
		restorationDurationTimer.setActive(false);
		
		flareCDTimer = new Timer(100);
		flareCDTimer.setActive(false);
		flareCastTimer = new Timer(100);
		flareCastTimer.setActive(false);
		
		flareOnCoolDown = false;
		flareCasting = false;
		
		decayOnCoolDown = false;
		decayDuration = false;
		targetDecay = null;
		
	    decaySkillLevel = 0;
	    restorationSkillLevel = 0;
	    flareSkillLevel = 0;
	    
	    this.setSkillUpgradePoints(10);
	}
    
    //SPRITE FRAME INFO
    //
    //
    public int[] getUpImages() {
        return new int[] {0,1,2};
    }
    public int[] getDownImages(){
        return new int[] {12,13,14};
    }
    public int[] getLeftImages(){
        return new int[] {18,19,20};
    }
    public int[] getRightImages(){
        return new int[] {6,7,8};
    }
    
    //ADDED//
    public int[] getUpFlinch(){
    	return new int[]{3,4,5};
    }
    
    public int[] getDownFlinch(){
    	return new int[]{15,16,17};
    }
    
    public int[] getLeftFlinch(){
    	return new int[]{21,22,23};
    }
    
    public int[] getRightFlinch(){
    	return new int[]{9,10,11};
    }

    //END ADDED//
	
    ///////////added - for buff <TEMP VALUES! UPDATE PLZ>
    public int[] getUpBuffed(){
    	return new int[]{24,25,26};
    }
    public int[] getDownBuffed(){
    	return new int[]{36,37,38}; 
    }
    public int[] getLeftBuffed(){
    	return new int[]{42,43,44};
    }
    public int[] getRightBuffed(){
    	return new int[]{30,31,32};
    }

    
	private static final long serialVersionUID = 1L;
	
	public double performNormalAttack()
	{
		double damage = super.performNormalAttack();
		
		//meaning player did not miss!
		if (damage != -1.0)
		{
			if (restorationDuration == true)
			{
				restoreSP(damage);
			}
		}
		return damage;
	}
	public void update(long elapsedTime)
	{
		//enable skills in skill bar if it's already unlocked
		if(decaySkillLevel>0){
			this.getSkillBar().btn1.setEnabled(true);
		}else
			this.getSkillBar().btn1.setEnabled(false);
		
		if(restorationSkillLevel>0){
			this.getSkillBar().btn2.setEnabled(true);
		}else
			this.getSkillBar().btn2.setEnabled(false);
		
		if(flareSkillLevel>0){
			this.getSkillBar().btn3.setEnabled(true);
		}else
			this.getSkillBar().btn3.setEnabled(false);
		
		performDecayDurationCheck(elapsedTime);
		performRestorationDurationCheck(elapsedTime);
		
		super.update(elapsedTime);
		
	}
	private void performDecayCDCheck (long elapsedTime)
	{
		if (decayCDTimer.action(elapsedTime) == true)
		{
			decayCDTimer.setActive(false);
			decayOnCoolDown = false;
		}
		
	}

	private void performDecayDurationCheck(long elapsedTime)
	{
		double magicAttackBonus;
		
		if (decayOnCoolDown != false)
		if (decayDurationTimer.action(elapsedTime) == true)
		{
			if (decayDurationCtr > 0)
			{
				if(targetDecay != null)
				{
					decayDurationCtr --;
					Statistics stat = this.getStatistics();
					magicAttackBonus = stat.getMAtk() * getDecayBonusValue();
					targetDecay.setBuffed(true);
					targetDecay.hit (this,stat.getMAtk() + magicAttackBonus); // hardcoded level 1 effect of skill

					System.out.println ("decay has caused magic damage: " + stat.getMAtk() * 2);
				
					if (restorationDuration == true)
						restoreSP(stat.getMAtk() * 2);
				}
				else
					decayDurationCtr = 0;
			}
			if (decayDurationCtr == 0)
			{
				decayDurationTimer.setActive(false);
				decayDuration = false;

				//if target isnt dead by the time decay duration ends
				if(getTarget() != null)
				{
					getTarget().setBuffed(false);
				}
				System.out.println("DECAY DOT has ended ***************");
				targetDecay = null;
			}
		}
		
	}
	
	private void performRestorationCDCheck (long elapsedTime)
	{
		if (restorationOnCoolDown != false) // meaning it hasnt been casted yet!
		if (restorationCDTimer.action(elapsedTime) == true)
		{
			restorationCDTimer.setActive(false);
			restorationOnCoolDown = false;
		}
	}
	
	private void performRestorationCastingCheck (long elapsedTime)
	{
//		if casting time wasn't interrupted and has finished
		if (restorationCasting != false) // meaning di pa sya nacast ._.
		if (restorationCastTimer.action(elapsedTime)== true)
		{
			restorationCastTimer.setActive(false); //stop timer
			if( restorationCasting = true) // nde nainterrupt
			{
				System.out.println ("Casting time finished===================");
			    performSkill2();
			}
		}
	}
	
	private void performRestorationDurationCheck (long elapsedTime)
	{
		if (restorationDurationTimer.action(elapsedTime))
		{
			restorationDurationTimer.setActive(false); 
			restorationDuration = false;
			System.out.println ("buff  restoration removed!! @@@@@@@@@@@@@@@@@@");
		}
	}
	
	private void restoreSP(double damage)
	{
		int value = new Double( damage * getRestorationBonusValue()).intValue();
		
		if (value <= 1)
			this.setCurrentMP (this.getCurrentMP () + 1);
		else
			this.setCurrentMP(this.getCurrentMP() + value);
	}
	
	/*************** MODIFIED *****************************/
	// skill commands are mapped here, instead of the main game class
	// skill bar sends commands here~
	// 
	@Override
	public void checkForSkillUse(long elapsedTime) {
		
		performDecayCDCheck(elapsedTime);
		performRestorationCDCheck(elapsedTime);
		performRestorationCastingCheck(elapsedTime);
		
		//flare casting
		performFlareCastingCheck(elapsedTime);
		
		if (getGame().keyPressed(KeyEvent.VK_1) || this.getSkillKeyUsed() == 1)
		{
			if(decaySkillLevel > 0)
			{
				if(hasTarget())
				{
					if (decayOnCoolDown == false)
				
					{
						performSkill1();
						this.setSkillKeyUsed(-1);
					}
					else
						System.out.println ("cant use skill yet!");
				}
			}
		}
		
			if (getGame().keyPressed(KeyEvent.VK_2) || this.getSkillKeyUsed() == 2)
			{
				if(restorationSkillLevel > 0)
				{
					if (restorationOnCoolDown == false)
					{
						restorationCasting = true; //start casting 
						restorationCastTimer.setActive(true); // start cooldown timer
						System.out.println ("Casting for restoration time started >>>>>>>>>>>>>>>>>>>>>>>>>");
						this.setSkillKeyUsed(-1);
					}	
				}
			}
			
			if (getGame().keyPressed(KeyEvent.VK_3) ||this.getSkillKeyUsed() == 3)
			{
				if(hasTarget())
				{
					if(flareSkillLevel > 0)
					{
						if(!flareOnCoolDown)
						{
						////// BUG ISSUE //////////////////////////////
						// [accuracy problem]						///
						// should be something like					///
						// (this.getCurrentMP() > this.bashMPcost)	///
						//											///
						// [refactoring shiz]						///
						// ang gulo amf, check for skill use...		///
						// but it also does half of skill checks na ///
						///////////////////////////////////////////////
							if(this.getCurrentMP() >  0)
							{
								flareCasting = true; //start casting
								flareCastTimer.setActive(true); //start casting timer
						
								this.setSkillKeyUsed(-1);
							
							}//skill mp check
						
						}//skill cooldown check end
					
					}//skill check end
				
				}//has target check end
			}
	}

	@Override
	public void performSkill1() {
		
		decayCDTimer.setActive(true);
		decayOnCoolDown = true;
		
		System.out.println("DECAY DOT has started ***************");
		
		
		decayDurationTimer.setActive(true); //dot starts!
		decayDuration = true;
		targetDecay = getTarget();
		
		this.setCurrentMP(new Double(this.getCurrentMP() - ( getMaxMP() * .3)).intValue());
		
		if (decaySkillLevel >= 6)
			decayDurationCtr = 10;
		else
			decayDurationCtr = 5;
		try
		{
			this.getGame().getParticleGroup().add(new HitSprite(this.getGame().getImages("IMAGES/Sprites/decay.png", 6, 1), getTarget().getX(), getTarget().getY()));
		}
		catch (NullPointerException e)
		{
			System.out.println (e.getMessage());
			if ( getTarget() == null)
				System.out.println ("nezie's hot!");
		}
	}

	private double getDecayBonusValue()
	{
		double bonus;
		switch (this.decaySkillLevel)
		{
			case 1: bonus = 1.0; break;
			case 2: bonus = 1.25; break;
			case 3: bonus = 1.5; break;
			case 4: bonus = 1.75; break;
			case 5: bonus = 2.0; break;
			case 6: bonus = 3.5; break;
			case 7: bonus = 4.5; break;
			case 8: bonus = 5.0; break;
			case 9: bonus = 5.5; break;
			case 10: bonus = 6.5; break;
			default: bonus = -1;
		}
		return bonus;
	}
	@Override
	public void performSkill2() {

		System.out.println ("Buff Restoration activated~~~~~~~~~~~~~~~~~~~~~~~~~");
		restorationDuration = true;
		restorationDurationTimer.setActive(true);
		
		this.setCurrentMP(new Double(this.getCurrentMP() - ( this.getMaxMP() * .5)).intValue());
		
	}
	
	private double getRestorationBonusValue()
	{
		double bonus;
		switch (this.restorationSkillLevel)
		{
			case 1: bonus = 0.01; break;
			case 2: bonus = 0.015; break;
			case 3: bonus = 0.02; break;
			case 4: bonus = 0.025; break;
			case 5: bonus = 0.03; break;
			case 6: bonus = 0.035; break;
			case 7: bonus = 0.04; break;
			case 8: bonus = 0.045; break;
			case 9: bonus = 0.05; break;
			case 10: bonus = 0.6; break;
			default: bonus = -1;
		}
		return bonus;
	}

	@Override
	public void performSkill3() {
		
		/****************************************
		 * 
		 * 	[ASSUMPTIONS]
		 * 
		 *  Currently has target, MP > 0
		 *  Skill level 
		 ****************************************/
		
		if(hasTarget())
		{
			System.out.println("Casting [FLARE] L." + flareSkillLevel);
			
			double FlareDamage = 5; //getFlareDamage(this.flareSkillLevel);
			
			System.out.println("[FLARE] L." + flareSkillLevel + " damages " + this.getTarget().getName() + " (" + FlareDamage + " DMG)");

			
			try
			{
				this.getGame().getAOEmanager().SetAOEdamage(FlareDamage);
				this.getGame().getAoEGroup().add(new HitSprite(this.getGame().getImages("IMAGES/Sprites/aoe.png", 4, 1), getTarget().getX() , getTarget().getY()));
				
				this.getGame().getAOEtimer().setActive(true);
				
			}
			catch (NullPointerException e)
			{
				System.out.println (e.getMessage());
				if ( getTarget() == null)
					System.out.println ("nezie's hot!");
			}

			this.setCurrentMP(new Double(this.getCurrentMP() - ( getMaxMP() * .2)).intValue());
		}
		
	}
	
	private double getFlareDamage(int level){
		double damage = 0;
		
		switch(level){
		case 1: {
			damage = this.getStatistics().getMAtk() * 0.8;
		}break;
		case 2: {
			damage = this.getStatistics().getMAtk() * 0.85;
		}break;
		case 3: {
			damage = this.getStatistics().getMAtk() * 0.9;
		}break;
		case 4: {
			damage = this.getStatistics().getMAtk() * 0.95;
		}break;
		case 5: {
			damage = this.getStatistics().getMAtk() * 1;
		}break;
		case 6: {
			damage = this.getStatistics().getMAtk() * 1.25;
		}break;
		case 7: {
			damage = this.getStatistics().getMAtk() * 1.3;
		}break;
		case 8: {
			damage = this.getStatistics().getMAtk() * 1.35;
		}break;
		case 9: {
			damage = this.getStatistics().getMAtk() * 1.4;
		}break;
		case 10: {
			damage = this.getStatistics().getMAtk() * 1.5;
		}break;
		
		}
		
		return damage;
	}

	public void checkIfLevelUp(int exp)
	{
		super.checkIfLevelUp(exp);
		//this.setStatistics(this.getLevelInfo().getNewElementalistStatistics(this.getLevel()));
	}
	
	public void configSkillbar(SkillBar s){
		this.setSkillBar(s);
		
		this.getSkillBar().btn1.setText("Decay");
		this.getSkillBar().btn2.setText("SpExg");
		this.getSkillBar().btn3.setText("Flare");
	}
	
	
	public void configSkillWindow(SkillWindow s){
		s.setSkill1("Decay", "Poison an enemy for 5 seconds", 0, (new Double( getMaxMP() * .3)).intValue(), 0);
		s.setSkill2("Restoration", "Gain MP for every successful attack", 0, new Double((this.getMaxMP() * .5)).intValue(), 2);
		s.setSkill3("[Flare]", "<AoE attack>", 0, new Double((this.getMaxMP() * .2)).intValue(), 1);
		
		this.setSkillWindow(s);
	}
	
	public void increaseSkill1(){
		
		decaySkillLevel++;
		this.setSkillUpgradePoints(this.getSkillUpgradePoints()-1);
		
		//UPDATE skillwindow info if nescessary~
		this.getSkillWindow().sk1sLevel.setText(((Integer)decaySkillLevel).toString());
		//MP calculation...ayusin
		this.getSkillWindow().sk1sCost.setText((new Double(this.getCurrentMP() - ( this.getMaxMP() * .15)).toString()));
		
		System.out.println("[PLAYER] Bash level increased to " + decaySkillLevel);
	}
	
	public void increaseSkill2(){
	
		restorationSkillLevel++;
		this.setSkillUpgradePoints(this.getSkillUpgradePoints()-1);
		System.out.println("[PLAYER] Restoration level increased to " + restorationSkillLevel);
		this.getSkillWindow().sk2sLevel.setText(((Integer)restorationSkillLevel).toString());
		//MP calculation...ayusin
		this.getSkillWindow().sk2sCost.setText((new Double(this.getCurrentMP() - ( this.getMaxMP() * .5)).toString()));
		
		
	}
	
	public void increaseSkill3(){
		flareSkillLevel++;
		this.setSkillUpgradePoints(this.getSkillUpgradePoints()-1);
		System.out.println("[PLAYER] Flare level increased to " + flareSkillLevel);
		this.getSkillWindow().sk3sLevel.setText(((Integer)flareSkillLevel).toString());
		//MP calculation...ayusin
		this.getSkillWindow().sk3sCost.setText((new Double(this.getCurrentMP() - ( this.getMaxMP() * .15)).toString()));
	}
	
	public int get1stSkillLevel(){
		return decaySkillLevel;
	}
	public int get2ndSkillLevel(){
		return restorationSkillLevel;
	}
	public int get3rdSkillLevel(){
		return 0;
	}
	
	private void performFlareCastingCheck(long elapsedTime)
	{
		//if casting time wasn't interrupted and has finished
		if(flareCastTimer.action(elapsedTime)== true)
		{
			flareCastTimer.setActive(false);//stop timer
			if(flareCasting = true) // if not interrupted
			{
				System.out.println("Flare cast successfully");
				performSkill3();
			}
		}
	}
	
}
